﻿using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Provider;
using System.Data.Entity;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Configuration;
using System.Web.Security;
using Tiscs.Practices.Diagnostics;
using Tiscs.Practices.Web.Providers.Entities;

namespace Tiscs.Practices.Web.Providers
{
    /// <summary>
    /// 用户凭据提供程序。
    /// </summary>
    public abstract class DefaultMembershipProvider : MembershipProvider
    {
        #region Abstract Methods

        /// <summary>
        /// 创建DbContext实例。
        /// </summary>
        /// <returns>DbContext实例。</returns>
        protected abstract DbContext CreateDbContext();

        #endregion

        #region Static Fields

        private static DateTime NullDate = new DateTime(1754, 1, 1);

        #endregion

        #region Static Methods

        private static string GetHashAlgorithmFromConfig()
        {
            try
            {
                MembershipSection membershipSection = ConfigurationManager.GetSection("system.web/membership") as MembershipSection;
                if (membershipSection != null)
                {
                    return membershipSection.HashAlgorithmType;
                }
            }
            catch (SecurityException)
            {
            }
            return null;
        }

        private static string GenerateSalt()
        {
            string result;
            using (RNGCryptoServiceProvider rNGCryptoServiceProvider = new RNGCryptoServiceProvider())
            {
                byte[] array = new byte[16];
                rNGCryptoServiceProvider.GetBytes(array);
                result = Convert.ToBase64String(array);
            }
            return result;
        }

        private static void ValidateStatus(int status)
        {
            if (status == 0)
            {
                return;
            }
            string exceptionText = DefaultMembershipProvider.GetExceptionText(status);
            if ((status >= 2 && status <= 6) || status == 99)
            {
                throw new MembershipPasswordException(exceptionText);
            }
            throw new ProviderException(exceptionText);
        }

        private static string GetExceptionText(int status)
        {
            switch (status)
            {
                case 0:
                    return string.Empty;
                case 1:
                    return ProvidersHelper.Membership_UserNotFound;
                case 2:
                    return ProvidersHelper.Membership_WrongPassword;
                case 3:
                    return ProvidersHelper.Membership_WrongAnswer;
                case 4:
                    return ProvidersHelper.Membership_InvalidPassword;
                case 5:
                    return ProvidersHelper.Membership_InvalidQuestion;
                case 6:
                    return ProvidersHelper.Membership_InvalidAnswer;
                case 7:
                    return ProvidersHelper.Membership_InvalidEmail;
                default:
                    if (status != 99)
                    {
                        return ProvidersHelper.Provider_Error;
                    }
                    return ProvidersHelper.Membership_AccountLockOut;
            }
        }

        #endregion

        #region Private Method

        private HashAlgorithm GetHashAlgorithm()
        {
            if (_hashAlgorithmName != null)
            {
                return HashAlgorithm.Create(_hashAlgorithmName);
            }
            string name = Membership.HashAlgorithmType;
            if (this.PasswordCompatMode == MembershipPasswordCompatibilityMode.Framework20 && !this.IsHashAlgorithmFromMembershipConfig && name != "MD5")
            {
                name = "SHA1";
            }
            HashAlgorithm hashAlgorithm = HashAlgorithm.Create(name);
            if (hashAlgorithm == null)
            {
                throw new ConfigurationErrorsException(string.Format(ProvidersHelper.Invalid_Hash_Algorithm, _hashAlgorithmName));
            }
            _hashAlgorithmName = name;
            return hashAlgorithm;
        }

        private string EncodeString(string source, int passwordFormat, string salt)
        {
            if (passwordFormat == 0)
            {
                return source;
            }
            byte[] sourceBytes = Encoding.Unicode.GetBytes(source);
            byte[] saltBytes = Convert.FromBase64String(salt);
            byte[] resultBytes;
            if (passwordFormat == 1)
            {
                HashAlgorithm hashAlgorithm = this.GetHashAlgorithm();
                KeyedHashAlgorithm keyedHashAlgorithm = hashAlgorithm as KeyedHashAlgorithm;
                if (keyedHashAlgorithm != null)
                {
                    if (keyedHashAlgorithm.Key.Length == saltBytes.Length)
                    {
                        keyedHashAlgorithm.Key = saltBytes;
                    }
                    else
                    {
                        if (keyedHashAlgorithm.Key.Length < saltBytes.Length)
                        {
                            byte[] keyBytes = new byte[keyedHashAlgorithm.Key.Length];
                            Buffer.BlockCopy(saltBytes, 0, keyBytes, 0, keyBytes.Length);
                            keyedHashAlgorithm.Key = keyBytes;
                        }
                        else
                        {
                            byte[] keyBytes = new byte[keyedHashAlgorithm.Key.Length];
                            int num;
                            for (int i = 0; i < keyBytes.Length; i += num)
                            {
                                num = Math.Min(saltBytes.Length, keyBytes.Length - i);
                                Buffer.BlockCopy(saltBytes, 0, keyBytes, i, num);
                            }
                            keyedHashAlgorithm.Key = keyBytes;
                        }
                    }
                    resultBytes = keyedHashAlgorithm.ComputeHash(sourceBytes);
                }
                else
                {
                    byte[] keyBytes = new byte[saltBytes.Length + sourceBytes.Length];
                    Buffer.BlockCopy(saltBytes, 0, keyBytes, 0, saltBytes.Length);
                    Buffer.BlockCopy(sourceBytes, 0, keyBytes, saltBytes.Length, sourceBytes.Length);
                    resultBytes = hashAlgorithm.ComputeHash(keyBytes);
                }
            }
            else
            {
                byte[] keyBytes = new byte[saltBytes.Length + sourceBytes.Length];
                Buffer.BlockCopy(saltBytes, 0, keyBytes, 0, saltBytes.Length);
                Buffer.BlockCopy(sourceBytes, 0, keyBytes, saltBytes.Length, sourceBytes.Length);
                resultBytes = this.EncryptPassword(keyBytes, this.PasswordCompatMode);
            }
            return Convert.ToBase64String(resultBytes);
        }

        private string UnEncodeString(string source, int passwordFormat)
        {
            switch (passwordFormat)
            {
                case 0:
                    return source;
                case 1:
                    throw new ProviderException(ProvidersHelper.Provider_Can_Not_Retrieve_Hashed_Password);
                default:
                    {
                        byte[] sourceBytes = Convert.FromBase64String(source);
                        byte[] resultBytes = this.DecryptPassword(sourceBytes);
                        if (resultBytes == null)
                        {
                            return null;
                        }
                        return Encoding.Unicode.GetString(resultBytes, 16, resultBytes.Length - 16);
                    }
            }
        }

        private string GetEncodedPasswordAnswer(MembershipEntity membership, string answer)
        {
            answer = answer?.Trim();
            return string.IsNullOrEmpty(answer) ? answer : this.EncodeString(answer, membership.PasswordFormat, membership.PasswordSalt);
        }

        private bool CheckPassword(MembershipEntity membership, UserEntity user, string password, bool updateLastActivityDate, bool failIfNotApproved)
        {
            DateTime utcNow = DateTime.UtcNow;
            if (membership == null || membership.IsLockedOut)
            {
                return false;
            }
            if (!membership.IsApproved && failIfNotApproved)
            {
                return false;
            }
            string strA = this.EncodeString(password, membership.PasswordFormat, membership.PasswordSalt);
            bool flag = string.Compare(strA, membership.Password, StringComparison.Ordinal) == 0;
            if (flag)
            {
                if (membership.FailedPasswordAttemptCount > 0 || membership.FailedPasswordAnswerAttemptCount > 0)
                {
                    membership.FailedPasswordAnswerAttemptCount = 0;
                    membership.FailedPasswordAnswerAttemptWindowsStart = DefaultMembershipProvider.NullDate;
                    membership.FailedPasswordAttemptCount = 0;
                    membership.FailedPasswordAttemptWindowStart = DefaultMembershipProvider.NullDate;
                    membership.LastLockoutDate = DefaultMembershipProvider.NullDate;
                }
            }
            else
            {
                if (utcNow > membership.FailedPasswordAttemptWindowStart.AddMinutes((double)this.PasswordAttemptWindow))
                {
                    membership.FailedPasswordAttemptCount = 1;
                }
                else
                {
                    membership.FailedPasswordAttemptCount++;
                }
                membership.FailedPasswordAttemptWindowStart = utcNow;
                if (membership.FailedPasswordAttemptCount >= this.MaxInvalidPasswordAttempts)
                {
                    membership.IsLockedOut = true;
                    membership.LastLockoutDate = utcNow;
                }
            }
            if (updateLastActivityDate)
            {
                membership.LastLoginDate = utcNow;
                if (user != null)
                {
                    user.LastActivityDate = utcNow;
                }
            }
            return flag;
        }

        private int CreateUser(string applicationName, string userName, string password, string salt, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out DateTime createDate, bool uniqueEmail, int passwordFormat, ref object providerUserKey)
        {
            createDate = DateTime.UtcNow;
            int result;
            using (DbContext db = CreateDbContext())
            {
                ApplicationEntity application = db.GetApplication(ApplicationName, true);
                Guid? inputId = (Guid?)providerUserKey;
                UserEntity user = db.GetUser(userName, this.ApplicationName);
                Guid? userId = user == null ? null : new Guid?(user.UserId);
                bool flag;
                if (userId.HasValue)
                {
                    flag = false;
                    if (inputId.HasValue && userId.Value != inputId.Value)
                    {
                        result = 6;
                        return result;
                    }
                }
                else
                {
                    if (inputId.HasValue)
                    {
                        if (db.GetUser(this.ApplicationName, inputId.Value) != null)
                        {
                            result = 10;
                            return result;
                        }
                        userId = new Guid?(inputId.Value);
                    }
                    else
                    {
                        userId = new Guid?(Guid.NewGuid());
                    }
                    UserEntity newUser = new UserEntity()
                    {
                        UserId = userId.Value,
                        ApplicationId = application.ApplicationId,
                        LastActivityDate = createDate,
                        UserName = userName,
                        IsAnonymous = false,
                    };
                    db.GetUsers().Add(newUser);
                    flag = true;
                }
                MembershipEntity membership = db.GetMembership(this.ApplicationName, userId.Value);
                if (membership == null)
                {
                    if (RequiresUniqueEmail)
                    {
                        if (db.GetMemberships(this.ApplicationName).Any(m => m.Email.ToLower() == email.ToLower()))
                        {
                            result = 7;
                            return result;
                        }
                    }
                    if (!flag)
                    {
                        user.LastActivityDate = createDate;
                    }
                    MembershipEntity membershipEntity = new MembershipEntity();
                    membershipEntity.ApplicationId = application.ApplicationId;
                    membershipEntity.CreateDate = createDate;
                    membershipEntity.Email = email;
                    membershipEntity.FailedPasswordAnswerAttemptCount = 0;
                    membershipEntity.FailedPasswordAnswerAttemptWindowsStart = DefaultMembershipProvider.NullDate;
                    membershipEntity.FailedPasswordAttemptCount = 0;
                    membershipEntity.FailedPasswordAttemptWindowStart = DefaultMembershipProvider.NullDate;
                    membershipEntity.IsApproved = isApproved;
                    membershipEntity.IsLockedOut = false;
                    membershipEntity.LastLockoutDate = DefaultMembershipProvider.NullDate;
                    membershipEntity.LastLoginDate = createDate;
                    membershipEntity.LastPasswordChangedDate = createDate;
                    membershipEntity.Password = password;
                    membershipEntity.PasswordAnswer = passwordAnswer;
                    membershipEntity.PasswordFormat = passwordFormat;
                    membershipEntity.PasswordQuestion = passwordQuestion;
                    membershipEntity.PasswordSalt = salt;
                    membershipEntity.UserId = userId.Value;
                    providerUserKey = userId.Value;
                    db.GetMemberships().Add(membershipEntity);
                    db.SaveChanges();
                    result = 0;
                }
                else
                {
                    result = 6;
                }
            }
            return result;
        }

        #endregion

        #region Private Fields

        private string _hashAlgorithmName;

        #endregion

        #region Private Properties

        private MembershipPasswordCompatibilityMode _passwordCompatMode;

        private MembershipPasswordCompatibilityMode PasswordCompatMode
        {
            get { return _passwordCompatMode; }
        }

        private Regex PasswordStrengthRegularRegex { get; set; }

        private bool? HashAlgorithmFromConfig { get; set; }

        private string _configHashAlgorithmType;

        private string ConfigHashAlgorithmType
        {
            get
            {
                return this._configHashAlgorithmType ?? DefaultMembershipProvider.GetHashAlgorithmFromConfig();
            }
            set
            {
                this._configHashAlgorithmType = value;
            }
        }

        private bool IsHashAlgorithmFromMembershipConfig
        {
            get
            {
                if (!HashAlgorithmFromConfig.HasValue)
                {
                    HashAlgorithmFromConfig = !string.IsNullOrEmpty(this.ConfigHashAlgorithmType);
                }
                return HashAlgorithmFromConfig.Value;
            }
        }

        #endregion

        #region MembershipProvider

        #region Properties

        /// <summary>
        /// 应用程序名称。
        /// </summary>
        public override string ApplicationName { get; set; }

        private bool _enablePasswordReset;

        /// <summary>
        /// 是否允许用户重置密码。
        /// </summary>
        public override bool EnablePasswordReset
        {
            get { return _enablePasswordReset; }
        }

        private bool _enablePasswordRetrieval;

        /// <summary>
        /// 是否允许用户检索密码。
        /// </summary>
        public override bool EnablePasswordRetrieval
        {
            get { return _enablePasswordRetrieval; }
        }

        private int _maxInvalidPasswordAttempts;

        /// <summary>
        /// 允许无效密码或无效安全答案的尝试次数。
        /// </summary>
        public override int MaxInvalidPasswordAttempts
        {
            get { return _maxInvalidPasswordAttempts; }
        }

        private int _minRequiredNonAlphanumericCharacters;

        /// <summary>
        /// 密码中包含特殊字符的最少数量。
        /// </summary>
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return _minRequiredNonAlphanumericCharacters; }
        }

        private int _minRequiredPasswordLength;

        /// <summary>
        /// 密码要求的最小长度。
        /// </summary>
        public override int MinRequiredPasswordLength
        {
            get { return _minRequiredPasswordLength; }
        }

        private int _passwordAttemptWindow;

        /// <summary>
        /// 由于无效密码或无效安全答案而锁定用户的分钟数。
        /// </summary>
        public override int PasswordAttemptWindow
        {
            get { return _passwordAttemptWindow; }
        }

        private MembershipPasswordFormat _passwordFormat;

        /// <summary>
        /// 密码和安全答案存储时的加密格式。
        /// </summary>
        public override MembershipPasswordFormat PasswordFormat
        {
            get { return _passwordFormat; }
        }

        private string _passwordStrengthRegularExpression;

        /// <summary>
        /// 用于验证密码强度的正则表达式。
        /// </summary>
        public override string PasswordStrengthRegularExpression
        {
            get { return _passwordStrengthRegularExpression; }
        }

        private bool _requiresQuestionAndAnswer;

        /// <summary>
        /// 安全问题和安全答案是否是必须的。
        /// </summary>
        public override bool RequiresQuestionAndAnswer
        {
            get { return _requiresQuestionAndAnswer; }
        }

        private bool _requiresUniqueEmail;

        /// <summary>
        /// 是否要求每个用户具有唯一的电子邮件地址。
        /// </summary>
        public override bool RequiresUniqueEmail
        {
            get { return _requiresUniqueEmail; }
        }

        #endregion

        /// <summary>
        /// 初始化成员资格提供程序。
        /// </summary>
        /// <param name="name">会话状态提供程序的友好名称。</param>
        /// <param name="config">会话状态提供程序初始化配置。</param>
        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "DefaultProfileProvider";
            }
            base.Initialize(name, config);
            _passwordFormat = config.GetConfigValue("passwordFormat", v => (MembershipPasswordFormat)Enum.Parse(typeof(MembershipPasswordFormat), v), MembershipPasswordFormat.Hashed);
            _enablePasswordRetrieval = config.GetConfigValue("enablePasswordRetrieval", Convert.ToBoolean, false);
            if (PasswordFormat == MembershipPasswordFormat.Hashed && EnablePasswordRetrieval)
            {
                throw new ProviderException(ProvidersHelper.Provider_Can_Not_Retrieve_Hashed_Password);
            }
            _passwordStrengthRegularExpression = config.GetConfigValue("passwordStrengthRegularExpression", Convert.ToString, string.Empty);
            if (!string.IsNullOrEmpty(PasswordStrengthRegularExpression))
            {
                try
                {
                    PasswordStrengthRegularRegex = new Regex(PasswordStrengthRegularExpression);
                }
                catch (ArgumentException ex)
                {
                    throw new ProviderException(ex.Message, ex);
                }
            }
            ApplicationName = config.GetConfigValue("applicationName", Convert.ToString, ProvidersHelper.GetDefaultApplicationName());
            _enablePasswordReset = config.GetConfigValue("enablePasswordReset", Convert.ToBoolean, true);
            _maxInvalidPasswordAttempts = config.GetConfigValue("maxInvalidPasswordAttempts", Convert.ToInt32, 5);
            _minRequiredNonAlphanumericCharacters = config.GetConfigValue("minRequiredNonalphanumericCharacters", Convert.ToInt32, 1);
            _minRequiredPasswordLength = config.GetConfigValue("minRequiredPasswordLength", Convert.ToInt32, 7);
            _passwordAttemptWindow = config.GetConfigValue("passwordAttemptWindow", Convert.ToInt32, 10);
            _requiresQuestionAndAnswer = config.GetConfigValue("requiresQuestionAndAnswer", Convert.ToBoolean, true);
            _requiresUniqueEmail = config.GetConfigValue("requiresUniqueEmail", Convert.ToBoolean, true);
            _passwordCompatMode = config.GetConfigValue("passwordCompatMode", v => (MembershipPasswordCompatibilityMode)Enum.Parse(typeof(MembershipPasswordCompatibilityMode), v), MembershipPasswordCompatibilityMode.Framework40);
            config.Remove("applicationName");
            config.Remove("enablePasswordReset");
            config.Remove("enablePasswordRetrieval");
            config.Remove("maxInvalidPasswordAttempts");
            config.Remove("minRequiredNonalphanumericCharacters");
            config.Remove("minRequiredPasswordLength");
            config.Remove("passwordAttemptWindow");
            config.Remove("passwordFormat");
            config.Remove("passwordStrengthRegularExpression");
            config.Remove("requiresQuestionAndAnswer");
            config.Remove("requiresUniqueEmail");
            config.Remove("passwordCompatMode");
            if (config.Count > 0)
            {
                throw new ProviderException(string.Format(ProvidersHelper.Unrecognized_Attribute, config.GetKey(0)));
            }
        }

        /// <summary>
        /// 处理更新成员资格用户密码的请求。
        /// </summary>
        /// <param name="userName">为其更新密码的用户。</param>
        /// <param name="oldPassword">指定的用户的当前密码。</param>
        /// <param name="newPassword">指定的用户的新密码。</param>
        /// <returns>如果密码更新成功，则为 true；否则为 false。</returns>
        public override bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            exception = Validation.Parameter<string>("oldPassword").AssertNotNullOrEmpty().AssertMaxLength(MembershipEntity.PasswordMaxLength).TrimAndValidate(ref oldPassword);
            if (exception != null)
            {
                throw exception;
            }
            exception = Validation.Parameter<string>("newPassword").AssertNotNullOrEmpty().AssertPasswordLength(MinRequiredPasswordLength, MembershipEntity.PasswordMaxLength).AssertPasswordMatchRegex(PasswordStrengthRegularRegex, MinRequiredNonAlphanumericCharacters).TrimAndValidate(ref newPassword);
            if (exception != null)
            {
                throw exception;
            }
            ValidatePasswordEventArgs validatePasswordEventArgs = new ValidatePasswordEventArgs(userName, newPassword, true);
            OnValidatingPassword(validatePasswordEventArgs);
            if (!validatePasswordEventArgs.Cancel)
            {
                bool result;
                using (DbContext db = CreateDbContext())
                {
                    MembershipEntity membership = db.GetMembership(ApplicationName, userName);
                    if (membership == null)
                    {
                        result = false;
                    }
                    else
                    {
                        if (this.CheckPassword(membership, null, oldPassword, false, false))
                        {
                            string password = this.EncodeString(newPassword, membership.PasswordFormat, membership.PasswordSalt);
                            membership.Password = password;
                            membership.LastPasswordChangedDate = DateTime.UtcNow;
                            db.SaveChanges();
                            result = true;
                        }
                        else
                        {
                            result = false;
                        }
                    }
                }
                return result;
            }
            if (validatePasswordEventArgs.FailureInformation != null)
            {
                throw validatePasswordEventArgs.FailureInformation;
            }
            throw new ArgumentException(ProvidersHelper.Membership_Custom_Password_Validation_Failure, "newPassword");
        }

        /// <summary>
        /// 处理更新成员资格用户的密码提示问题和答案的请求。
        /// </summary>
        /// <param name="userName">要为其更改密码提示问题和答案的用户。</param>
        /// <param name="password">指定的用户的密码。</param>
        /// <param name="newPasswordQuestion">指定的用户的新密码提示问题。</param>
        /// <param name="newPasswordAnswer">指定的用户的新密码提示问题答案。</param>
        /// <returns>如果成功更新密码提示问题和答案，则为 true；否则，为 false。</returns>
        public override bool ChangePasswordQuestionAndAnswer(string userName, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            exception = Validation.Parameter<string>("password").AssertNotNullOrEmpty().AssertPasswordLength(MinRequiredPasswordLength, MembershipEntity.PasswordMaxLength).AssertPasswordMatchRegex(PasswordStrengthRegularRegex, MinRequiredNonAlphanumericCharacters).TrimAndValidate(ref password);
            if (exception != null)
            {
                throw exception;
            }
            exception = Validation.Parameter<string>("newPasswordQuestion").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordQuestionMaxLength).TrimAndValidate(ref newPasswordQuestion);
            if (exception != null)
            {
                throw exception;
            }
            exception = Validation.Parameter<string>("newPasswordAnswer").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordAnswerMaxLength).TrimAndValidate(ref newPasswordAnswer);
            if (exception != null)
            {
                throw exception;
            }
            bool result;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(ApplicationName, userName);
                if (membership == null)
                {
                    result = false;
                }
                else
                {
                    string passwordAnswer;
                    if (string.IsNullOrEmpty(newPasswordAnswer))
                    {
                        passwordAnswer = newPasswordAnswer;
                    }
                    else
                    {
                        passwordAnswer = this.EncodeString(newPasswordAnswer, membership.PasswordFormat, membership.PasswordSalt);
                    }
                    exception = Validation.Parameter<string>("newPasswordAnswer").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordAnswerMaxLength).Validate(passwordAnswer);
                    if (exception != null)
                    {
                        throw exception;
                    }
                    membership.PasswordQuestion = newPasswordQuestion;
                    membership.PasswordAnswer = newPasswordAnswer;
                    db.SaveChanges();
                    result = true;
                }
            }
            return result;
        }

        /// <summary>
        /// 将新的成员资格用户添加到数据源。
        /// </summary>
        /// <param name="userName">新用户的用户名。</param>
        /// <param name="password">新用户的密码。</param>
        /// <param name="email">新用户的电子邮件地址。</param>
        /// <param name="passwordQuestion">新用户的密码提示问题。</param>
        /// <param name="passwordAnswer">新用户的密码提示问题答案。</param>
        /// <param name="isApproved">是否允许验证新用户。</param>
        /// <param name="providerUserKey">成员资格数据源中该用户的唯一标识符。</param>
        /// <param name="status">一个<see cref="MembershipCreateStatus"/>枚举值，指示是否已成功创建用户。</param>
        /// <returns>一个用新创建的用户的信息填充的<see cref="MembershipUser"/>对象。</returns>
        public override MembershipUser CreateUser(string userName, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            string salt = DefaultMembershipProvider.GenerateSalt();
            bool valresult = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().TrimAndCheckRules(ref userName);
            if (!valresult)
            {
                status = MembershipCreateStatus.InvalidUserName;
                return null;
            }
            valresult = Validation.Parameter<string>("password").AssertNotNullOrEmpty().AssertMaxLength(MembershipEntity.PasswordMaxLength).TrimAndCheckRules(ref password);
            if (!valresult)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }
            valresult = Validation.Parameter<string>("email").AssertNotNullOrEmptyIfTrue(RequiresUniqueEmail).AssertMaxLength(MembershipEntity.EmailMaxLength).TrimAndCheckRules(ref email);
            if (!valresult)
            {
                status = MembershipCreateStatus.InvalidEmail;
                return null;
            }
            valresult = Validation.Parameter<string>("passwordQuestion").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordQuestionMaxLength).TrimAndCheckRules(ref passwordQuestion);
            if (!valresult)
            {
                status = MembershipCreateStatus.InvalidQuestion;
                return null;
            }
            passwordAnswer = string.IsNullOrEmpty(passwordAnswer) ? passwordAnswer : EncodeString(passwordAnswer, (int)this.PasswordFormat, salt);
            valresult = Validation.Parameter<string>("passwordAnswer").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordAnswerMaxLength).TrimAndCheckRules(ref passwordAnswer);
            if (!valresult)
            {
                status = MembershipCreateStatus.InvalidAnswer;
                return null;
            }
            ValidatePasswordEventArgs validatePasswordEventArgs = new ValidatePasswordEventArgs(userName, password, true);
            this.OnValidatingPassword(validatePasswordEventArgs);
            if (validatePasswordEventArgs.Cancel)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }
            DateTime dateTime;
            int num2 = this.CreateUser(this.ApplicationName, userName, EncodeString(password, (int)this.PasswordFormat, salt), salt, email, passwordQuestion, passwordAnswer, isApproved, out dateTime, this.RequiresUniqueEmail, (int)this.PasswordFormat, ref providerUserKey);
            if (num2 < 0 || num2 > 11)
            {
                num2 = 11;
            }
            status = (MembershipCreateStatus)num2;
            if (status != 0)
            {
                return null;
            }
            return new MembershipUser(Name, userName, providerUserKey, email, passwordQuestion, null, isApproved, false, dateTime, dateTime, dateTime, dateTime, DefaultMembershipProvider.NullDate);
        }

        /// <summary>
        /// 从成员资格数据源删除一个用户。
        /// </summary>
        /// <param name="userName">要删除的用户的名称。</param>
        /// <param name="deleteAllRelatedData">如果为 true，则从数据库中删除与该用户相关的数据；如果为 false，则将与该用户相关的数据保留在数据库。</param>
        /// <returns>如果用户被成功删除，则为 true；否则为 false。</returns>
        public override bool DeleteUser(string userName, bool deleteAllRelatedData)
        {
            userName = userName == null ? null : userName.Trim();
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().Validate(userName);
            if (exception != null)
            {
                throw exception;
            }
            bool result;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(ApplicationName, userName);
                if (membership == null)
                {
                    result = false;
                }
                else
                {
                    db.GetMemberships().Remove(membership);
                    if (deleteAllRelatedData)
                    {
                        UserEntity user = db.GetUser(ApplicationName, userName);
                        user.Roles.Clear();
                        user.Profile = null;
                        db.GetUsers().Remove(user);
                    }
                    db.SaveChanges();
                    result = true;
                }
            }
            return result;
        }

        /// <summary>
        /// 获取一个成员资格用户的集合，其中的电子邮件地址包含要匹配的指定电子邮件地址。
        /// </summary>
        /// <param name="emailToMatch">要搜索的电子邮件地址。</param>
        /// <param name="pageIndex">要返回的结果页的索引。从零开始。</param>
        /// <param name="pageSize">要返回的结果页的大小。</param>
        /// <param name="totalRecords">匹配用户的总数。</param>
        /// <returns>搜索到的<see cref="MembershipUser"/>对象集合。</returns>
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            ParameterValidator<string> validator = Validation.Parameter<string>("emailToMatch");
            if (RequiresUniqueEmail)
            {
                validator.AssertNotNullOrEmpty();
            }
            Exception exception = validator.AssertMaxLength(MembershipEntity.EmailMaxLength).TrimAndValidate(ref emailToMatch);
            if (exception != null)
            {
                throw exception;
            }
            MembershipUserCollection result = new MembershipUserCollection();
            using (DbContext db = CreateDbContext())
            {
                IQueryable<MembershipEntity> queryable = db.GetMemberships(ApplicationName);
                if (string.IsNullOrEmpty(emailToMatch))
                {
                    queryable = queryable.Where(m => m.Email.ToLower().Contains(emailToMatch.ToLower()));
                }
                totalRecords = queryable.Count();
                if (pageIndex != -1 && pageSize != -1)
                {
                    queryable = queryable.Skip(pageIndex * pageSize).Take(pageSize);
                }
                foreach (MembershipEntity membership in queryable)
                {
                    result.Add(membership.ToMembershipUser(this.Name));
                }
            }
            return result;
        }

        /// <summary>
        /// 获取一个成员资格用户的集合，其中的用户名包含要匹配的指定用户名。
        /// </summary>
        /// <param name="userNameToMatch">要搜索的用户名。</param>
        /// <param name="pageIndex">要返回的结果页的索引。从零开始。</param>
        /// <param name="pageSize">要返回的结果页的大小。</param>
        /// <param name="totalRecords">匹配用户的总数。</param>
        /// <returns>搜索到的<see cref="MembershipUser"/>对象集合。</returns>
        public override MembershipUserCollection FindUsersByName(string userNameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            Exception exception = Validation.Parameter<string>("userNameToMatch").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).TrimAndValidate(ref userNameToMatch);
            if (exception != null)
            {
                throw exception;
            }
            MembershipUserCollection result = new MembershipUserCollection();
            using (DbContext db = CreateDbContext())
            {
                IQueryable<MembershipEntity> queryable = db.GetMemberships(ApplicationName);
                if (string.IsNullOrEmpty(userNameToMatch))
                {
                    queryable = queryable.Where(m => m.User.UserName.ToLower().Contains(userNameToMatch.ToLower()));
                }
                totalRecords = queryable.Count();
                if (pageIndex != -1 && pageSize != -1)
                {
                    queryable = queryable.Skip(pageIndex * pageSize).Take(pageSize);
                }
                foreach (MembershipEntity membership in queryable)
                {
                    result.Add(membership.ToMembershipUser(this.Name));
                }
            }
            return result;
        }

        /// <summary>
        /// 获取数据源中的所有用户的集合，并显示在数据页中。
        /// </summary>
        /// <param name="pageIndex">要返回的结果页的索引。从零开始。</param>
        /// <param name="pageSize">要返回的结果页的大小。</param>
        /// <param name="totalRecords">匹配用户的总数。</param>
        /// <returns>搜索到的<see cref="MembershipUser"/>对象集合。</returns>
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection result = new MembershipUserCollection();
            using (DbContext db = CreateDbContext())
            {
                IQueryable<MembershipEntity> queryable = db.GetMemberships(ApplicationName);
                totalRecords = queryable.Count();
                if (pageIndex != -1 && pageSize != -1)
                {
                    queryable = queryable.Skip(pageIndex * pageSize).Take(pageSize);
                }
                foreach (MembershipEntity membership in queryable)
                {
                    result.Add(membership.ToMembershipUser(this.Name));
                }
            }
            return result;
        }

        /// <summary>
        /// 获取当前访问该应用程序的用户数。
        /// </summary>
        /// <returns>当前访问该应用程序的用户数。</returns>
        public override int GetNumberOfUsersOnline()
        {
            DateTime dateactive = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes((double)Membership.UserIsOnlineTimeWindow));
            int result;
            using (DbContext db = CreateDbContext())
            {
                result = db.GetMemberships(ApplicationName).Where(m => m.User.LastActivityDate > dateactive).Count();
            }
            return result;
        }

        /// <summary>
        /// 从数据源获取指定用户名所对应的密码。
        /// </summary>
        /// <param name="userName">为其检索密码的用户。</param>
        /// <param name="answer">用户的密码提示问题答案。</param>
        /// <returns>指定用户名所对应的密码。</returns>
        public override string GetPassword(string userName, string answer)
        {
            if (!EnablePasswordRetrieval)
            {
                throw new NotSupportedException(ProvidersHelper.Membership_PasswordRetrieval_Not_Supported);
            }
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            int num = 0;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(this.ApplicationName, userName);
                if (membership == null)
                {
                    num = 1;
                }
                else
                {
                    if (membership.IsLockedOut)
                    {
                        num = 99;
                    }
                    else
                    {
                        DateTime utcNow = DateTime.UtcNow;
                        string answer1 = null;
                        if (answer != null)
                        {
                            answer1 = this.GetEncodedPasswordAnswer(membership, answer);
                        }
                        ParameterValidator<string> validator = Validation.Parameter<string>("passwordAnswer").AssertMaxLength(MembershipEntity.PasswordAnswerMaxLength);
                        if (RequiresQuestionAndAnswer)
                        {
                            validator.AssertNotNullOrEmpty();
                        }
                        exception = validator.Validate(answer1);
                        if (exception != null)
                        {
                            throw exception;
                        }
                        if (this.RequiresQuestionAndAnswer && membership.PasswordAnswer != null)
                        {
                            if (string.Equals(answer1, membership.PasswordAnswer))
                            {
                                membership.FailedPasswordAnswerAttemptWindowsStart = utcNow;
                                if (utcNow > membership.FailedPasswordAnswerAttemptWindowsStart.AddMinutes((double)this.PasswordAttemptWindow))
                                {
                                    membership.FailedPasswordAttemptCount = 1;
                                }
                                else
                                {
                                    membership.FailedPasswordAttemptCount++;
                                }
                                if (membership.FailedPasswordAnswerAttemptCount >= this.MaxInvalidPasswordAttempts)
                                {
                                    membership.IsLockedOut = true;
                                    membership.LastLockoutDate = utcNow;
                                }
                                num = 3;
                            }
                            else
                            {
                                if (membership.FailedPasswordAnswerAttemptCount > 0)
                                {
                                    membership.FailedPasswordAnswerAttemptCount = 0;
                                    membership.FailedPasswordAnswerAttemptWindowsStart = DefaultMembershipProvider.NullDate;
                                }
                            }
                            db.SaveChanges();
                        }
                    }
                }
                if (num == 0 && membership.Password != null)
                {
                    return this.UnEncodeString(membership.Password, membership.PasswordFormat);
                }
            }
            DefaultMembershipProvider.ValidateStatus(num);
            return null;
        }

        /// <summary>
        /// 从数据源获取用户的信息。 提供一个更新用户最近一次活动的日期/时间戳的选项。
        /// </summary>
        /// <param name="userName">要获取其信息的用户名。</param>
        /// <param name="userIsOnline">如果为 true，则更新用户最近一次活动的日期/时间戳；如果为 false，则返回用户信息，但不更新用户最近一次活动的日期/时间戳。</param>
        /// <returns>用数据源中指定用户的信息填充的<see cref="MembershipUser"/>对象。</returns>
        public override MembershipUser GetUser(string userName, bool userIsOnline)
        {
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertNoCommas().AssertMaxLength(UserEntity.UserNameMaxLength).TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            MembershipUser membershipUser;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(this.ApplicationName, userName);
                membershipUser = membership == null ? null : membership.ToMembershipUser(this.Name);
                if (userIsOnline)
                {
                    if (membership.User != null)
                    {
                        membership.User.LastActivityDate = DateTime.UtcNow;
                        db.SaveChanges();
                    }
                }
            }
            return membershipUser;
        }

        /// <summary>
        /// 根据成员资格用户的唯一标识符从数据源获取用户信息。 提供一个更新用户最近一次活动的日期/时间戳的选项。
        /// </summary>
        /// <param name="providerUserKey">要获取其信息的成员资格用户的唯一标识符。</param>
        /// <param name="userIsOnline">如果为 true，则更新用户最近一次活动的日期/时间戳；如果为 false，则返回用户信息，但不更新用户最近一次活动的日期/时间戳。</param>
        /// <returns>用数据源中指定用户的信息填充的<see cref="MembershipUser"/>对象。</returns>
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            Exception exception = Validation.Parameter<object>("providerUserKey").AssertNotNull().Assert(p => p is Guid, n => new ArgumentException(ProvidersHelper.Membership_InvalidProviderUserKey)).Validate(providerUserKey);
            if (exception != null)
            {
                throw exception;
            }
            MembershipUser membershipUser;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(this.ApplicationName, (Guid)providerUserKey);
                membershipUser = membership == null ? null : membership.ToMembershipUser(this.Name);
                if (userIsOnline)
                {
                    if (membership.User != null)
                    {
                        membership.User.LastActivityDate = DateTime.UtcNow;
                        db.SaveChanges();
                    }
                }
            }
            return membershipUser;
        }

        /// <summary>
        /// 获取与指定的电子邮件地址关联的用户名。
        /// </summary>
        /// <param name="email">要搜索的电子邮件地址。</param>
        /// <returns>与指定的电子邮件地址关联的用户名。 如果未找到匹配项，则返回 null。</returns>
        public override string GetUserNameByEmail(string email)
        {
            Exception exception = Validation.Parameter<string>("email").AssertNotNullOrEmptyIfTrue(RequiresUniqueEmail).AssertMaxLength(MembershipEntity.EmailMaxLength).TrimAndValidate(ref email);
            if (exception != null)
            {
                throw exception;
            }
            string email1;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMemberships(this.ApplicationName).Where(m => m.Email != null && m.Email.ToLower() == email.ToLower()).FirstOrDefault();
                email1 = membership == null ? null : membership.Email;
            }
            return email1;
        }

        /// <summary>
        /// 将用户密码重置为一个自动生成的新密码。 
        /// </summary>
        /// <param name="userName">为其重置密码的用户。</param>
        /// <param name="answer">指定的用户的密码提示问题答案。</param>
        /// <returns>指定的用户的新密码。</returns>
        public override string ResetPassword(string userName, string answer)
        {
            if (!this.EnablePasswordReset)
            {
                throw new NotSupportedException(ProvidersHelper.Not_configured_to_support_password_resets);
            }
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertNoCommas().AssertMaxLength(UserEntity.UserNameMaxLength).TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            string text = Membership.GeneratePassword((this.MinRequiredPasswordLength < 14) ? 14 : this.MinRequiredPasswordLength, this.MinRequiredNonAlphanumericCharacters);
            ValidatePasswordEventArgs validatePasswordEventArgs = new ValidatePasswordEventArgs(userName, text, false);
            this.OnValidatingPassword(validatePasswordEventArgs);
            if (!validatePasswordEventArgs.Cancel)
            {
                int status = 0;
                DateTime utcNow = DateTime.UtcNow;
                using (DbContext db = CreateDbContext())
                {
                    MembershipEntity membership = db.GetMembership(this.ApplicationName, userName);
                    if (membership == null)
                    {
                        status = 1;
                    }
                    else
                    {
                        if (membership.IsLockedOut)
                        {
                            status = 99;
                        }
                        else
                        {
                            string answer1;
                            if (!string.IsNullOrEmpty(answer))
                            {
                                answer1 = this.EncodeString(answer, membership.PasswordFormat, membership.PasswordSalt);
                            }
                            else
                            {
                                answer1 = answer;
                            }
                            exception = Validation.Parameter<string>("answer").AssertNotNullOrEmptyIfTrue(RequiresQuestionAndAnswer).AssertMaxLength(MembershipEntity.PasswordAnswerMaxLength).TrimAndValidate(ref answer1);
                            if (answer == null || string.Equals(membership.PasswordAnswer, answer1))
                            {
                                membership.Password = this.EncodeString(text, membership.PasswordFormat, membership.PasswordSalt);
                                membership.LastPasswordChangedDate = DateTime.UtcNow;
                                if (membership.FailedPasswordAnswerAttemptCount > 0)
                                {
                                    membership.FailedPasswordAnswerAttemptCount = 0;
                                    membership.FailedPasswordAnswerAttemptWindowsStart = DefaultMembershipProvider.NullDate;
                                }
                            }
                            else
                            {
                                if (utcNow > membership.FailedPasswordAnswerAttemptWindowsStart.AddMinutes((double)this.PasswordAttemptWindow))
                                {
                                    membership.FailedPasswordAnswerAttemptCount = 1;
                                }
                                else
                                {
                                    membership.FailedPasswordAnswerAttemptCount++;
                                }
                                membership.FailedPasswordAnswerAttemptWindowsStart = utcNow;
                                if (membership.FailedPasswordAnswerAttemptCount >= this.MaxInvalidPasswordAttempts)
                                {
                                    membership.IsLockedOut = true;
                                    membership.LastLockoutDate = utcNow;
                                }
                                status = 3;
                            }
                            db.SaveChanges();
                        }
                    }
                }
                DefaultMembershipProvider.ValidateStatus(status);
                return text;
            }
            if (validatePasswordEventArgs.FailureInformation != null)
            {
                throw validatePasswordEventArgs.FailureInformation;
            }
            throw new ProviderException(ProvidersHelper.Membership_Custom_Password_Validation_Failure);
        }

        /// <summary>
        /// 清除锁定，以便可以验证该成员资格用户。
        /// </summary>
        /// <param name="userName">要清除其锁定状态的成员资格用户。</param>
        /// <returns>如果成功取消成员资格用户的锁定，则为 true；否则为 false。</returns>
        public override bool UnlockUser(string userName)
        {
            Exception exception = Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertNoCommas().AssertMaxLength(UserEntity.UserNameMaxLength).TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            bool result;
            using (DbContext db = CreateDbContext())
            {
                MembershipEntity membership = db.GetMembership(this.ApplicationName, userName);
                if (membership != null)
                {
                    membership.IsLockedOut = false;
                    membership.FailedPasswordAnswerAttemptCount = 0;
                    membership.FailedPasswordAnswerAttemptWindowsStart = DefaultMembershipProvider.NullDate;
                    membership.FailedPasswordAttemptCount = 0;
                    membership.FailedPasswordAttemptWindowStart = DefaultMembershipProvider.NullDate;
                    membership.LastLockoutDate = DefaultMembershipProvider.NullDate;
                    db.SaveChanges();
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            return result;
        }

        /// <summary>
        /// 更新数据源中有关用户的信息。
        /// </summary>
        /// <param name="user">一个<see cref="MembershipUser"/>对象，表示要更新的用户及其更新信息。</param>
        public override void UpdateUser(MembershipUser user)
        {
            string userName = user.UserName;
            Exception exception = Validation.Parameter<string>("user.UserName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).AssertNoCommas().TrimAndValidate(ref userName);
            if (exception != null)
            {
                throw exception;
            }
            string email = user.Email;
            ParameterValidator<string> validator = Validation.Parameter<string>("user.Email").AssertMaxLength(MembershipEntity.EmailMaxLength);
            if (this.RequiresUniqueEmail)
            {
                validator.AssertNotNullOrEmpty();
            }
            exception = validator.Validate(email);
            if (exception != null)
            {
                throw exception;
            }
            using (DbContext db = CreateDbContext())
            {
                int num = 0;
                Guid? guid = (Guid?)user.ProviderUserKey;
                if (!guid.HasValue)
                {
                    num = 1;
                }
                if (num == 0 && this.RequiresUniqueEmail && db.GetMemberships(this.ApplicationName).Any(m => m.Email.ToLower() == email.ToLower() && m.UserId != guid.Value))
                {
                    num = 7;
                }
                if (num == 0)
                {
                    MembershipEntity membership = db.GetMembership(this.ApplicationName, user.UserName);
                    if (membership != null && membership.User != null)
                    {
                        membership.User.LastActivityDate = user.LastActivityDate.ToUniversalTime();
                        membership.Email = user.Email;
                        membership.Comment = user.Comment;
                        membership.IsApproved = user.IsApproved;
                        membership.LastLoginDate = user.LastLoginDate.ToUniversalTime();
                    }
                    db.SaveChanges();
                }
                else
                {
                    DefaultMembershipProvider.ValidateStatus(num);
                }
            }
        }

        /// <summary>
        /// 验证数据源中是否存在指定的用户名和密码。
        /// </summary>
        /// <param name="userName">要验证的用户的名称。</param>
        /// <param name="password">指定的用户的密码。</param>
        /// <returns>如果指定的用户名和密码有效，则为 true；否则为 false。</returns>
        public override bool ValidateUser(string userName, string password)
        {
            if (Validation.Parameter<string>("password").AssertNotNullOrEmpty().AssertMaxLength(MembershipEntity.PasswordMaxLength).TrimAndCheckRules(ref password))
            {
                if (Validation.Parameter<string>("userName").AssertNotNullOrEmpty().AssertMaxLength(UserEntity.UserNameMaxLength).TrimAndCheckRules(ref userName))
                {
                    using (DbContext db = CreateDbContext())
                    {
                        MembershipEntity membership = db.GetMembership(this.ApplicationName, userName);
                        if (membership == null)
                        {
                            return false;
                        }
                        else
                        {
                            bool result = this.CheckPassword(membership, membership.User, password, true, true);
                            db.SaveChanges();
                            return result;
                        }
                    }
                }
            }
            return false;
        }

        #endregion
    }
}
